package eureka.consumer.redissonlock;

import eureka.consumer.redissonlock.interfaces.DistributedLockTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.TransportMode;
import org.springframework.beans.factory.FactoryBean;

import javax.annotation.PreDestroy;

/**
 * @Author RenPu
 * @Date 2021/8/26 11:29
 * @Version 1.0
 * @Description: 交由SpringFactoryBean进行管理，针对销毁，获取单例分布式锁对象
 **/
@Slf4j
public class DistributedLockFactoryBean implements FactoryBean<DistributedLockTemplate> {

    private LockInstanceMode mode;

    private DistributedLockTemplate distributedLockTemplate;

    private final RedissonClient redisson;



    /**
     * 初始化Redisson配置参数，构建RedissonClient对象
     * @param redissonProperty
     */
    public DistributedLockFactoryBean(BaseRedisProperty redissonProperty) {
        log.info("init redisson: {}", redissonProperty.toString());
        String ip = redissonProperty.getHost();
        Integer port = redissonProperty.getPort();

        BaseRedisProperty.Redisson redisson = redissonProperty.getRedisson();
        Config config = new Config();
        if (TransportMode.EPOLL.name().equalsIgnoreCase(redisson.getTransportMode())) {
            config.setTransportMode(TransportMode.EPOLL);
        }
        SingleServerConfig singleServer = config.useSingleServer();
        singleServer.setAddress("redis://" + ip + ":" + port);
        singleServer.setTimeout(redisson.getTimeOut());
        singleServer.setConnectionPoolSize(redisson.getPoolSize());
        // redis密码校验
        if (StringUtils.isNotEmpty(redissonProperty.getPassword())) {
            log.info("redisson 密码不为空，设置密码");
            singleServer.setPassword(redissonProperty.getPassword());
        }
        singleServer.setPingConnectionInterval(1000);
        singleServer.setConnectionMinimumIdleSize(redisson.getMinIdleSize());
        this.redisson = Redisson.create(config);
        setMode(redisson.getMode());
    }


    /**
     * RedissonClient对象销毁得方法
     */
    @PreDestroy
    public void destroy() {
        log.info("销毁Redisson分布式锁模板");
        redisson.shutdown();
    }


    /**
     *  获取单例分布式锁对象
     * @return
     * @throws Exception
     */
    @Override
    public DistributedLockTemplate getObject() throws Exception {
        switch (mode) {
            case SINGLE:
                distributedLockTemplate = new SingleDistributedLockTemplate(redisson);
                break;
        }
        return distributedLockTemplate;
    }


    /**
     * 获取对象类型
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return DistributedLockTemplate.class;
    }

    /**
     * 是否属于单例
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }


    /**
     * 构建单例分布式锁
     * @param mode
     */
    private void setMode(String mode) {
        if (mode == null || mode.length() <= 0 || mode.equals("")) {
            throw new IllegalArgumentException("未找到redisson.mode配置项");
        }
        this.mode = LockInstanceMode.parse(mode);
        if (this.mode == null) {
            throw new IllegalArgumentException("不支持的分布式锁模式");
        }
    }


    /**
     * 枚举类
     */
    private enum LockInstanceMode {
        SINGLE;

        public static LockInstanceMode parse(String name) {
            for (LockInstanceMode modeIns : LockInstanceMode.values()) {
                if (modeIns.name().equals(name.toUpperCase())) {
                    return modeIns;
                }
            }
            return null;
        }
    }
}
